
/*    This file is part of the Managarm operating system.
 *   Copyright (C) 2007, 2008, 2009  Alexander van der Grinten
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

package org.managarm.jmanacclib.generic;

// import managarm virtual architecture
import org.managarm.jmanavalib.core.VaDatatype;
import org.managarm.jmanavalib.core.VaMthInfo;
import org.managarm.jmanavalib.core.VaFldInfo;
import org.managarm.jmanavalib.core.VaLiteral;

public class GnInst {
	// loads a literal into a register
	public final static class InstLoad extends GnInst {
		public final int register;
		public final VaLiteral value;
		
		public InstLoad(int register, VaLiteral value) {
			this.register = register;
			this.value = value;
		}
	}
	
	// returns from a procedure
	public final static class InstReturn extends GnInst {
		public final int register;
		
		public InstReturn(int register) {
			this.register = register;
		}
	}
	
	// applies a binary operator to two registers and stores the result
	public final static class InstBinOperation extends GnInst {
		// operator constants
		public static final int OP_ARITH_ADD = 1;
		public static final int OP_ARITH_SUB = 2;
		public static final int OP_ARITH_MUL = 3;
		public static final int OP_ARITH_DIV = 4;
		public static final int OP_ARITH_MOD = 5;
		public static final int OP_ARITH_OR = 6;
		public static final int OP_ARITH_AND = 7;
		public static final int OP_ARITH_XOR = 8;
		public static final int OP_ARITH_SHL = 9;
		public static final int OP_ARITH_SHR = 10;
		public static final int OP_SETIF_EQUALS = 11;
		public static final int OP_SETIF_ABOVE = 12;
		public static final int OP_SETIF_BELOW = 13;

		public final int operator;
		public final int register;
		public final int left;
		public final int right;
		
		public InstBinOperation(int operator, int register,
				int left, int right) {
			this.operator = operator;
			this.register = register;
			this.left = left;
			this.right = right;
		}
	}
	
	// applies a unary operator to a register and stores
	// the result in a virtual register
	public final static class InstUnOperation extends GnInst {
		public static final int OP_ARITH_NEG = 1;
		public static final int OP_ARITH_NOT = 2;
		public static final int OP_ARR_SIZE = 3;
		
		public final int operator;
		public final int register;
		public final int operand;
		
		public InstUnOperation(int operator, int register,
				int operand) {
			this.operator = operator;
			this.register = register;
			this.operand = operand;
		}
	}
	
	// clones a virtual register
	public final static class InstClone extends GnInst {
		public final int register;
		public final int operand;
		
		public InstClone(int register, int operand) {
			this.register = register;
			this.operand = operand;
		}
	}
	
	// jumps to/invokes a frame
	public final static class InstJump extends GnInst {
		public final int frameId;
		public final int register;
		
		public InstJump(final int frameid, final int register) {
			this.frameId = frameid;
			this.register = register;
		}
	}
	
	// invokes a method
	public final static class InstInvoke extends GnInst {
		public final VaMthInfo mthInfo;
		public final int object;
		public final int result;
		public final boolean virtual;
		private final int[] arguments;
		
		public InstInvoke(VaMthInfo method, int object, int result,
				boolean virtual, int[] arguments) {
			this.mthInfo = method;
			this.object = object;
			this.result = result;
			this.virtual = virtual;
			this.arguments = arguments.clone();
		}
		
		// returns the number of arguments
		public final int getArgumentCnt() {
			return arguments.length;
		}
		
		// returns the argument register at "index"
		public final int getArgument(int index) {
			return arguments[index];
		}
	}
	
	// creates a new object of a class and
	// stores a reference to it in a virtual register
	public final static class InstCreateObject extends GnInst {
		public final VaDatatype datatype;
		public final int register;
		
		public InstCreateObject(VaDatatype datatype, int register) {
			this.datatype = datatype;
			this.register = register;
		}
	}
	
	// creates a new array and stores a reference to it in a virtual register
	public final static class InstCreateArray extends GnInst {
		public final VaDatatype datatype;
		public final int size;
		public final int register;
		
		public InstCreateArray(VaDatatype datatype, int size, int register) {
			this.datatype = datatype;
			this.size = size;
			this.register = register;
		}
	}
	
	// accesses an array element
	public final static class InstArrAccess extends GnInst {
		public static final int OP_STORE = 1;
		public static final int OP_LOAD = 2;
		
		public final int operator;
		public final int array;
		public final int index;
		public final int operand;
		
		public InstArrAccess(int operator, int array,
				int index, int operand) {
			this.array = array;
			this.operator = operator;
			this.index = index;
			this.operand = operand;
		}
	}
	
	// loads or stores a virtual register into a static
	// field or into an object field
	public final static class InstFldAccess extends GnInst {
		public static final int OP_STORE = 1;
		public static final int OP_LOAD = 2;
		
		public final VaFldInfo fldInfo;
		public final int operator;
		public final int object;
		public final int operand;
		
		public InstFldAccess(int operator, VaFldInfo fldinfo,
				int object, int operand) {
			this.fldInfo = fldinfo;
			this.operator = operator;
			this.object = object;
			this.operand = operand;
		}
	}
	
	// casts a register to a different type and stores the
	// new reference in a virtual register
	public final static class InstCast extends GnInst {
		public final VaDatatype datatype;
		public final int source;
		public final int dest;
		
		public InstCast(VaDatatype datatype, int dest, int source) {
			this.datatype = datatype;
			this.dest = dest;
			this.source = source;
		}
	}
	
	// writes true into a virtual register if "object" is
	// an object of class "clsInfo". otherwise false is written
	// into the register
	public final static class InstInstanceof extends GnInst {
		public final VaDatatype datatype;
		public final int object;
		public final int register;
		
		public InstInstanceof(VaDatatype datatype, int object, int register) {
			this.datatype = datatype;
			this.object = object;
			this.register = register;
		}
	}

	public final static class InstDlgConstruct extends GnInst {
		public final VaMthInfo method;
		public final int object;
		public final int result;
		
		public InstDlgConstruct(final VaMthInfo method,
				final int object, final int result) {
			this.method = method;
			this.object = object;
			this.result = result;
		}
	}
	
	public final static class InstThrow extends GnInst {
		public final int exception;
		
		public InstThrow(final int exception) {
			this.exception = exception;
		}
	}
	
	public final static class InstCatch extends GnInst {
		public final int exception;
		public final GnProcedure procedure;
		public final int frame;
		
		public InstCatch(final int exception,
				final int frame, final GnProcedure procedure) {
			this.exception = exception;
			this.frame = frame;
			this.procedure = procedure;
		}
	}
	
	public final static class InstLeave extends GnInst {
		
	}
	
	public final static class InstXNatMthAddress extends GnInst {
		public final VaMthInfo mthInfo;
		public final int dest;
		
		public InstXNatMthAddress(int dest, VaMthInfo mthinfo) {
			this.mthInfo = mthinfo;
			this.dest = dest;
		}
	}
	
	public final static class InstXNatSizeofObject extends GnInst {
		public final VaDatatype datatype;
		public final int dest;
		
		public InstXNatSizeofObject(int dest, VaDatatype datatype) {
			this.datatype = datatype;
			this.dest = dest;
		}
	}
	
	public final static class InstXNatAddressCast extends GnInst {
		public final VaDatatype datatype;
		public final int dest;
		public final int source;
		
		public InstXNatAddressCast(int dest, int source, VaDatatype datatype) {
			this.datatype = datatype;
			this.dest = dest;
			this.source = source;
		}
	}
	
	public final static class InstXNatAddressOf extends GnInst {
		public static final int ADDRESS_OBJECT = 1;
		public static final int ADDRESS_DLG_OBJECT = 2;
		public static final int ADDRESS_DLG_METHOD = 3;
		
		public final int address;
		public final int object;
		public final int result;
		
		public InstXNatAddressOf(int address, int object, int result) {
			this.address = address;
			this.object = object;
			this.result = result;
		}
	}

	public final static class InstXNatMakeDelegate extends GnInst {
		public final VaDatatype datatype;
		public final int method;
		public final int object;
		public final int result;
		
		public InstXNatMakeDelegate(final VaDatatype datatype,
				final int method, final int object, final int result) {
			this.datatype = datatype;
			this.method = method;
			this.object = object;
			this.result = result;
		}
	}
	
	public final static class InstXNatRefOperation extends GnInst {
		public static final int REF_INCREMENT = 1;
		public static final int REF_DECREMENT = 2;
		
		public final int operation;
		public final int register;
		
		public InstXNatRefOperation(final int operation, final int register) {
			this.operation = operation;
			this.register = register;
		}
	}
	
	public final static class InstXAtomCas extends GnInst {
		public final VaFldInfo field;
		public final int object;
		public final int dest;
		public final int source;
		public final int value;
		
		public InstXAtomCas(int object, VaFldInfo field,
				int source, int value, int dest) {
			this.field = field;
			this.object = object;
			this.source = source;
			this.value = value;
			this.dest = dest;
		}
	}
	
	public final static class InstXPerfArrayCopy extends GnInst {
		public final int dest;
		public final int source;
		public final int destOffset;
		public final int sourceOffset;
		public final int size;
		
		public InstXPerfArrayCopy(int dest, int source,
				int destoff, int srcoff, int size) {
			this.dest = dest;
			this.source = source;
			this.destOffset = destoff;
			this.sourceOffset = srcoff;
			this.size = size;
		}
	}
}
